
package cz.czu.pef.DataModelling.ejb.impl;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.*;
import javax.interceptor.Interceptors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cz.czu.pef.DataModelling.*;
import cz.czu.pef.DataModelling.dao.*;
import cz.czu.pef.DataModelling.ejb.api.*;

@Service(value="personService")
// ##################################################
// JBOSS6 CR1 has a lot of ClassLoading issues => even moving EJB JAR to WAR didn't help => disable EJB completely for this moment
// - also change app-prod-service.xml to lookup for EJB's JNDI again...
// ##################################################
@Stateless(name = "personServiceEJB", mappedName="personServiceEJB")
@Remote
// ##################################################
// Note: SpringBeanAutowiringInterceptor requires beanRefContext.xml to be defined (on EAR level)
// ##################################################
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class PersonServiceImpl extends AbstractWrapperServiceImpl<Person> implements AbstractWrapperService<Person>
{
	Logger logger = Logger.getLogger(PersonServiceImpl.class.getName());
	
	@Autowired PersonDao personDao;
	
	@Override
	public Dao<Person> getDao()
	{
		return personDao;
	}

	@Transactional(timeout=30, propagation=Propagation.REQUIRED, readOnly=true)
	public String runDemo()
	{
		try
		{
			logger.log(Level.INFO, "runDemo():: Entry");

			personDao.merge(new Person("TEST FIRST", "TEST LAST"));

			return "Hibernate zavolan";
		}
		catch (Throwable th)
		{
			System.out.println("Exception: " + th.getStackTrace());
			return "Chyba pri zpracovani: " + th.getStackTrace();
		}
		finally
		{
			logger.log(Level.INFO, "runDemo():: Exit");
		}
	}

	@Transactional(timeout=30, propagation=Propagation.REQUIRES_NEW, readOnly=false)
	public void addPerson(Person person)
	{
		System.out.println("addPerson():: Entry");
		personDao.merge(person);
		System.out.println("addPerson():: Exit");
	}

	@Transactional(timeout=30, propagation=Propagation.REQUIRES_NEW, readOnly=false)
	public void removePersonById(long personId)
	{
		System.out.println("removePersonById():: Entry");
		personDao.deleteById(personId + "");
		System.out.println("removePersonById():: Exit");
	}

	@Transactional(timeout=30, propagation=Propagation.REQUIRES_NEW, readOnly=true)
	public List<Person> listPeople()
	{
		return personDao.findAll();
	}
	
	@Override
	@Transactional(timeout=30, propagation=Propagation.REQUIRES_NEW, readOnly=true)
	public boolean canBeRemoved(Person entity)
	{
		if (entity == null)
			return true;
		// FIXME: Workarounds for LazyInitializationException: no session or session was closed. Is this the correct way in 3-layer architecture? 
		// javax.ejb.EJBException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cz.czu.pef.DataModelling.Person.machineries, no session or session was closed

		// 1. try:
		// org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter in web.xml
		    //  and access the object directly in web-layer => not working

		// 2. try:
		// wrap it in EJB service (this method)
		    // not working since the object itself is still detached

		// 3. try:
		// Hibernate.initialize(entity);
		    // not working, don't know why....

		// 4.try
        // initialize the object again so it will participate in current transaction 
		entity = getDao().getById(entity.getId());
		if (entity == null)
			return true;

		// 5.try - disable lazy-loading completely (not recommended due to performance and memory allocation reasons!)

		return entity.canBeRemoved();
	}


}
